/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.bookmarksframework.core
{
	import flash.utils.Dictionary;
	
	[ExcludeClass]
	public class Storage implements IStorage
	{
		protected var dictionary:Dictionary;
		
		protected var map:XML;
		
		public function Storage()
		{
			map = <map/>;
			dictionary = new Dictionary();
		}
		
		public function getParent(facileKey:*):FacileHierarchy
		{
			var result:FacileHierarchy = null;
			var child:XML = facileKey as XML;
			var parent:XML = (child) ? child.parent() : null;
			var parentItem:FacileHierarchy;
			
			if (parent && parent.childIndex() >= 0)
			{
				parentItem = getItem(parent);
				result = new FacileHierarchy(this, parent, 
					parentItem ? parentItem.value : null);
			}
			
			return result;
		}
		
		public function getChildren(facileKey:* = null):Vector.<FacileHierarchy>
		{
			var scope:IStorage = this;
			
			var f:Function = function(children:XMLList):Vector.<FacileHierarchy>
			{
				var result:Vector.<FacileHierarchy> = new Vector.<FacileHierarchy>();
				var childrenLen:int = children.length();
				var hierarchy:FacileHierarchy;
				var child:XML;
				
				for (var i:int = 0; i < childrenLen; ++i)
				{
					child = children[i];
					hierarchy = getItem(child);
					result.push(hierarchy);
				}
				
				return result;
			};
			
			return f((facileKey is XML) ? facileKey.children() : map.children());
		}
		
		public function getKey(value:*):*
		{
			var result:* = null;
			
			if (value is IFragment)
			{
				result = (contains(value)) ? 
					map.descendants(value.uid)[0] : null; 
			}
			else if (value is String)
			{
				result = (dictionary[value]) ? 
					map.descendants(value)[0] : null;
			}
			
			return result;
		}
		
		public function getItem(facileKey:*):FacileHierarchy
		{
			var result:FacileHierarchy = null;
			
			if ((facileKey is XML) && 
				dictionary[facileKey.localName()])
			{
				result = new FacileHierarchy(this, facileKey, 
					dictionary[facileKey.localName()]);
			}
			
			return result; 
		}
		
		public function store(controller:IFragmentController):Boolean
		{
			var fragment:IFragment = controller.fragment;
			var fragmentUID:String = fragment.uid;
			var parent:IFragment = fragment.parent;
			var parentNode:XML;
			var child:XML;
			var result:Boolean = false;
			
			if (!map.descendants(fragmentUID)[0])
			{
				child = <{fragmentUID}/>;
				
				if (!parent)
				{
					map.appendChild(child);
				}
				else if ((parentNode = map.descendants(parent.uid)[0]))
				{
					parentNode.appendChild(child);
				}
				
				dictionary[fragmentUID] = controller;
				result = true;
			}
			
			return result;
		}
		
		public function unstore(controller:IFragmentController):Boolean
		{
			var fragment:IFragment = controller.fragment;
			var fragmentUID:String = fragment.uid;
			var child:XML;
			var descendans:XMLList;
			var result:Boolean = false;
			
			if ((child = map.descendants(fragmentUID)[0]))
			{
				descendans = child.descendants("*");
				
				for (var j:int = 0; j < descendans.length(); ++j)
				{
					delete dictionary[descendans[j].localName()];
				}
				
				delete dictionary[child.localName()];
				delete child.parent().children()[child.childIndex()];
				result = true;
			}
			
			return result;
		}
		
		public function contains(fragment:IFragment):Boolean
		{
			return (dictionary[fragment.uid] != null);
		}
		
	}
}